import type { DirectiveBinding } from "vue";

type TrackInfoType = {
  opt_label: string;
  category?: string;
  opt_extra?: {
    [key: string]: any;
  };
};

export default defineNuxtPlugin(async (nuxtApp) => {
  const trackApi = useTrackApi();

  const createTackDirective = () => {
    let observer: IntersectionObserver | undefined;

    const trackFn = (currentTarget: HTMLElement, type: "show" | "click") => {
      // const currentTarget = (evt.currentTarget || evt.target) as HTMLElement;

      if (currentTarget.dataset.track_info) {
        try {
          const trackInfo = JSON.parse(
            currentTarget.dataset.track_info,
          ) as TrackInfoType[];

          /**
           * 按道理来说应该接口接受一个数组，否则上报请求实在太多
           */
          if (trackInfo && trackInfo.length) {
            trackInfo.forEach((info) => {
              trackApi.track({
                category: "page",
                action: type,
                opt_label: info.opt_label,
                opt_extra: info.opt_extra,
              });
            });
          }
        } catch (e) {
          console.error(e);
        }
      }
    };

    const clickTrackFn = (evt: Event) =>
      trackFn(evt.currentTarget as HTMLElement, "click");
    const showTrackFn = (currentTarget: HTMLElement) =>
      trackFn(currentTarget, "show");

    const setAttr = (el: HTMLElement, binding: DirectiveBinding<any>) => {
      // 还得需要兼容数组
      if (binding.value) {
        if (binding.value instanceof Array) {
          el.dataset.track_info = JSON.stringify(binding.value);
        } else {
          el.dataset.track_info = JSON.stringify([binding.value]);
        }
      }
    };

    nuxtApp.vueApp.directive("track", {
      mounted(el, binding) {
        const arg = binding.arg as "click" | "exposure";

        setAttr(el, binding);

        if (arg === "click") {
          el.addEventListener("click", clickTrackFn);
        }

        /**
         * 记录显示隐藏的埋点
         * 本项目不需要记录曝光时长的埋点
         * 如有需要用另一个库 https://github.com/M-cheng-web/web-tracing
         */
        if (arg === "exposure") {
          observer = new IntersectionObserver((entries) => {
            entries.forEach((entry) => {
              // 可见
              if (entry.isIntersecting) {
                // console.log("可见埋点");
                showTrackFn(entry.target as HTMLElement);
              } else {
                // console.log("不可见埋点");
              }
            });
          });
          observer.observe(el);
        }
      },
      unmounted(el) {
        observer?.unobserve?.(el);
        el?.removeEventListener("click", clickTrackFn);
      },
      updated(el, binding) {
        setAttr(el, binding);
      },
    });
  };

  createTackDirective();
});
